package com.pvdnc.systemdebugger.compacter;

import android.annotation.SuppressLint;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;

import java.lang.reflect.Method;

public class PBServiceManager extends Binder implements IPBServiceManager {
    private static final String TAG="PBServiceManager";

    private static void addServiceImpl(String name,IBinder local){
        try {
            @SuppressLint("PrivateApi") Class<?> ServiceManager=Class.forName("android.os.ServiceManager");
            Method addService=ServiceManager.getDeclaredMethod("addService",String.class,IBinder.class);
            addService.setAccessible(true);
            addService.invoke(null,name,local);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static IBinder getServiceImpl(String name){
        try {
            @SuppressLint("PrivateApi") Class<?> ServiceManager=Class.forName("android.os.ServiceManager");
            Method getService=ServiceManager.getDeclaredMethod("getService",String.class);
            getService.setAccessible(true);
            return (IBinder) getService.invoke(null,name);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String[] listServices(){
        try {
            @SuppressLint("PrivateApi") Class<?> ServiceManager=Class.forName("android.os.ServiceManager");
            Method getService=ServiceManager.getDeclaredMethod("listServices");
            getService.setAccessible(true);
            return (String[]) getService.invoke(null);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void registerSelf(){
        addServiceImpl(SELF_SERVICE_NAME,new PBServiceManager());
    }

    public static PBServiceManagerProxy getSelf(){
        return new PBServiceManagerProxy(getServiceImpl(SELF_SERVICE_NAME));
    }

    @Override
    public void addService(String name, IBinder local) {
        int fromPid=Binder.getCallingPid();
        Log.d(TAG,"add service:"+name+" request from pid:"+fromPid);
        addServiceImpl(name, local);
    }

    @Override
    public IBinder getService(String name) {
        int fromPid=Binder.getCallingPid();
        Log.d(TAG,"get service:"+name+" request from pid:"+fromPid);
        return getServiceImpl(name);
    }

    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        switch (code){
            case CODE_ADD_SERVICE:{
                String name=data.readString();
                IBinder local=data.readStrongBinder();
                addService(name,local);
                reply.writeInt(REMOTE_SUCCESS);
                break;
            }
            case CODE_GET_SERVICE:{
                String name=data.readString();
                IBinder remote=getService(name);
                reply.writeStrongBinder(remote);
                break;
            }
            default:{
                return false;
            }
        }
        return true;
    }

    @Override
    public IBinder asBinder() {
        return this;
    }
}
